#ifndef __MISC_INC__
#define __MISC_INC__

#define beat_2_csec(beat, bpm) (beat*1500)/bpm

//A stupid process we manipulate from the outside
Process robot()
Begin
  graph=0;
  while(die == 0)
    FRAME;
  end;
End;


/*---------------------------------------------------------------------
The following three functions behave mostly like their PHP equivalents
---------------------------------------------------------------------*/

//Remove all the spaces and slashes from the begining and the end of
//the string (ust like PHP does)
Function string _trim(string str)
Private
  int i=0, strlen=0;

Begin
  while(str[i] == " " || str[i] == "-")
    i++;
  end;
  strlen = len(str);
  str = substr(str, i, strlen);
  strlen -= i;
  i=1;
  while(str[strlen-i] == " " || str[strlen-i] == "-")
    i++;
  end;
  str = substr(str, 0, strlen-i+1);
  return str;
End;

//Remove all the spaces and slashes from the begining of
//the string (ust like PHP does)
Function string _ltrim(string str)
Private
  int i=0, strlen=0;

Begin
  while(str[i] == " " || str[i] == "-")
    i++;
  end;
  strlen = len(str);
  str = substr(str, i, strlen);
  return str;
End;

//Remove all the spaces and slashes from the end of
//the string (ust like PHP does)
Function string _rtrim(string str)
Private
  int i=1, strlen=0;
  
Begin
  while(str[strlen-i] == " " || str[strlen-i] == "-")
    i++;
  end;
  str = substr(str, 0, strlen-i+1);
  return str;
End;

// Given a directory, this function tries to create it, and all the
// required upper directories
Function create_dir_hierarchy(string new_directory)
Private
string current_directory="";
string partial_route[10]; // 10 dirs at max
int i=0;
int i_max=0;

Begin

  current_directory = cd(); 
  if(chdir(new_directory) == 0) // The dir already exists!
    cd(current_directory);
    return 0;
  end;

  i_max = split("[\/]", new_directory, &partial_route, 10);
  chdir("/");
  while (i<i_max)
    while(partial_route[ i ] == "") // Skip blank dirnames
      if(i++ >=i_max)
        cd(current_directory);
        return 0;
      end;
    end;
    if(chdir(partial_route[ i ]) == -1)
      if(mkdir(partial_route[ i ]) == -1) // Couldn't create dir :(
        cd(current_directory);
        return -1;
      end;
      chdir(partial_route[ i ]);
    end;
    i++;
  end;
  chdir(current_directory);
  return 0;
End;

// Set the variable containing the directory used to store your config
// And create the directory, if it didn't exist
Function set_savegamepath()
Begin
  savegamedir = getenv(custompath) + "/" + developerpath;
  if(create_dir_hierarchy(savegamedir) == -1)
    say("Error, I couldn't create the savegame directory, games won't be saved");
    //TODO: Prevent savegame writing
  end;
End;

// This process controls the mouse, making it appear or disappear as needed
Process mouse_controller()
Private
  int mouse_deact_delay=300, old_mouse_x=0, old_mouse_y=0;
  int mouse_graph=0, mouse_act_time=0;
End

Begin
  // Load the mouse graph
  mouse_graph = load_png(datadir+"img/mouse.png");
  set_point(0, mouse_graph, 0, 0, 0);
  old_mouse_x = mouse.x; old_mouse_y = mouse.y;
  
  while(die == 0)
    // Check if the mouse should appear
    if(mouse.x != old_mouse_x || mouse.y != old_mouse_y)
      mouse_act_time = timer[0];
      if(mouse.graph == 0)
        mouse.graph = mouse_graph;
      end;
    end;

    // Make the mouse disappear, if needed
    if( (mouse.graph != 0) && (timer[0] > mouse_act_time + mouse_deact_delay) )
      mouse.graph = 0;
    end;
    
    // Store the previous mouse position to check if it moved
    old_mouse_x = mouse.x; old_mouse_y = mouse.y;
    FRAME;
  end;
  
  unload_map(0, mouse_graph);
End;

// This function is in charge of finding songs in your songs dir.
// The process requires a bit of heuristics, as we're opening any .txt
// file in every subdir of the Songs folder and trying to preparse it.
// If we get valid data from that file, we assume that's the file with
// the song lyrics. If we don't get that data, we try again with every
// file on the dir, until giving up...
Function find_songs()
Private
  int i=0, fd=0, pos=0;
  string fname="", charset="", line="";
  string dirs[MAX_ALLOWED_SONGS]; // Here we're placing the limit of songs
End

Begin
  // Only look for songs the first time the menu is loaded
  // If in previous checks we didn't find any, repeat.
  if(songs_found == 0)
    dbg_print("Finding songs in "+datadir+"Songs/");

    //Find all the directories
    while( glob(datadir+"Songs/*") != "")
      if(fileinfo.directory && fileinfo.name != ".." && fileinfo.name != ".")
        dirs[i++] = fileinfo.path+"/"+fileinfo.name+"/";
      end;
    end;

    // Now scan each directory for a single song, this defines the structure of
    // your songs dir.
    //
    // Be aware that this can be a slow operation.
    dbg_print("Going to look for songs.");
    for(i=0; i<MAX_ALLOWED_SONGS; i++)
      // We'll look for every .txt, and only accept the first one with valid data
      if(glob(dirs[i]+"/*.txt") != "")
        // Try to parse some very simple data
        songs[i].dirname = fileinfo.path;
        songs[i].filename = fileinfo.name;
        songs[i].coverpath = datadir+"/img/cover_not_found.png";
        fname = fileinfo.path+"/"+fileinfo.name;
        fd = fopen(fname, O_READ);
        if(fd != 0)
          while(!feof(fd))
            line = fgets(fd);
            line = _trim(line);
            if(line[0] == ":")  // End of header, lyrics start
              break;
            end;
            if((pos = find(line, "#TITLE:")) != -1)
              songs[i].title=substr(line, pos+len("#TITLE:"));
            elif((pos = find(line, "#MP3:")) != -1)
              songs[i].music_file = songs[i].dirname+substr(line, pos+len("#MP3:"));
            elif((pos = find(line, "#ARTIST:")) != -1)
              songs[i].artist = substr(line, pos+len("#ARTIST:"));
            elif((pos = find(line, "#BACKGROUND:")) != -1)
              songs[i].bgpath = songs[i].dirname+substr(line, pos+len("#BACKGROUND:"));
            elif((pos = find(line, "#COVER:")) != -1)
              songs[i].coverpath = songs[i].dirname+substr(line, pos+len("#COVER:"));
            end;
          end;

          // Close the file descriptor, we don't need it anymore.
          fclose(fd);

          dbg_print("Parsed song "+songs[i].title+" from "+songs[i].artist+
            " with cover at"+songs[i].coverpath);
        else    // Filename doesn't exist
          songs[i].dirname="";
          songs[i].filename="";
        end;
        
        // Try again if data couldn't be retrieved
        if(fileinfo.name != "" && songs[i].title=="")
          songs[i].filename = songs[i].dirname = "";
          i--;
        else
          songs_found++;
        end;
      end;
      //Loading the cover art is done when going to show it for the first time
    end;

    if(songs_found > 0)
      dbg_print("====================================================");
      dbg_print("");
      dbg_print("");
      dbg_print("These are the songs I found:");
      for(i=0; i<songs_found; i++)
        dbg_print(songs[i].title);
      end;
      dbg_print("");
      dbg_print("");
      dbg_print("====================================================");
    end;
    
    // A quick run to determine the charsets & convert the titles
    // Cannot do this because of how glob works
    for(i=0; i < songs_found; i++)
      if(songs[i].title == "")
        songs[i].title = "Untitled";
      end;
      if(songs[i].dirname != "" && songs[i].filename != "")
        charset = determine_charset(songs[i].dirname+"/"+songs[i].filename);
        dbg_print("Using charset "+charset+" for file "+songs[i].filename);
        // Convert the data to UTF-8
        songs[i].title=iconv(charset, "UTF8//TRANSLIT", songs[i].title);
        songs[i].artist=iconv(charset, "UTF8//TRANSLIT", songs[i].artist);
        // To workaround a bug in Bennu, instead of FRAME(0)'ing, I glob
        // another dir.
        glob("/tmp/*");
      end;
    end;
    
  end;

  desc_file_finished=0;    //Just in case
End;


// Renders a cover with its title below it
Function render_cover(string coverpath, string title)
Private
  int cover_graph=0, tmp=0, tmp2=0, cover_width=0, cover_height=0;
  int title_width=0, title_height=0, i=0, j=0, r=0, g=0, b=0, a=0;
  int total_width=0, total_height=0;
  float scale_factor=1.0, reflection_factor=1.2;

Begin
  if(file_exists(coverpath))
    #ifdef NO_REFLECTION
      reflection_factor = 1.0;
    #endif
    // Load the cover
    dbg_print("Going to try to load: "+coverpath+" as "+title);
    //Load the cover, erase the transparent parts & rescale it
    tmp = load_image(coverpath);
    cover_height = graphic_info(0, tmp, G_HEIGHT);
    cover_width = graphic_info(0, tmp, G_WIDTH);
    tmp2 = pango_render('<span font_family="'+song_font+
           '" weight="bold" font="20" color="#FFFF00">'
           +title+'</span>');
    title_width = graphic_info(0, tmp2, G_WIDTH);
    title_height = graphic_info(0, tmp2, G_HEIGHT);
    scale_factor = cover_height/(resy/2);    
    
    total_width = cover_width/scale_factor;
    total_height = cover_height/scale_factor + title_height;
    if(title_width > total_width)
      total_width = title_width;
    end;
    dbg_print("scale_factor: "+scale_factor);
    cover_graph = map_new( total_width, reflection_factor * total_height, BPP);

    // We'll draw a black box below the cover, to compensate for transparent
    // pixels in the loaded map.
    drawing_map (0, cover_graph); drawing_color(rgba(0, 0, 0, 255));
    draw_box((total_width-cover_width/scale_factor)/2, 0,
             cover_width/scale_factor, cover_height/scale_factor - 1);
    // Blit the song cover
    map_xput(0, cover_graph, tmp, total_width/2, cover_height/(scale_factor*2), 0,
             100 / scale_factor, 0);
    // Blit the song name
    map_block_copy(0, cover_graph, (total_width - title_width)/2,
             total_height - title_height,
             tmp2, 0, 0, title_width, title_height, B_NOCOLORKEY );

    // Unload the temporary maps
    unload_map(0, tmp);
    unload_map(0, tmp2);


    // Draw a reflection under the cover image, but only if told to do so
    #ifndef NO_REFLECTION
      for(i=total_height; i <= total_height*reflection_factor; i++)
        a = 0.65 * 255 * ( 1.0 - (i-total_height)/((reflection_factor-1.0)*total_height) );
        for(j=0; j < total_width; j++)
          tmp = map_get_pixel(0, cover_graph, j, 2*total_height-i-title_height );
          get_rgba(tmp, &r, &g, &b, &tmp2);
          // Paint the pixel, if it's not transparent
          if(tmp != 0 && tmp2 != 0 && a != 0)
            map_put_pixel(0, cover_graph, j, i, rgba(r, g, b, a) );
          end;
        end;
      end;
    #endif

  end;
  
  return cover_graph;
End;

// This routine pre-renders the covers, with their name and reflection
// but trying not to block the system.
Process pre_render_covers()
Private
  int i=0, maxi=0;
End

Begin
  // We can safely assume there found_songs > 0, because the karaoke
  // refuses to start otherwise.
  maxi = (songs_found/2) + 1;
  for(i=0; i<=maxi; i++)
    if(songs[i].cover == 0)
      dbg_print("Need to render "+songs[i].coverpath);
      songs[i].cover = render_cover(songs[i].coverpath, songs[i].title);
    end;
    covers_rendered++;
    // Load the following cover
    if(songs[songs_found-i].cover == 0)
      dbg_print("Need to render "+songs[songs_found-i].coverpath);
      songs[songs_found-i].cover = render_cover(songs[songs_found-i].coverpath,
                                                songs[songs_found-i].title);
    end;
    covers_rendered++;
  end;
End;

#endif
